package com.ruoyi.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.ruoyi.system.domain.SysVideo;
import com.ruoyi.system.domain.VideoChannel;
import com.ruoyi.system.domain.dtos.HotVideoDto;
import com.ruoyi.system.mapper.SysVideoMapper;
import com.ruoyi.system.mapper.VideoChannelMapper;
import com.ruoyi.system.service.IHotVideoService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.joda.time.DateTime;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class HotVideoServiceImpl implements IHotVideoService {

    @Autowired
    private SysVideoMapper sysVideoMapper;

    /**
     * 计算热门视频
     */
    @Override
    public void computeHotArticle() {
        // 1. 查询前5天的视频数据
        Date dayParam = DateTime.now().minusDays(5).toDate();
        List<SysVideo> videoList = sysVideoMapper.findVideoListByLast5days(dayParam);

        // 2. 计算视频的分值
        List<HotVideoDto> hotVideoDtoList = getHotVideoDtoList(videoList);

        // 3. 缓存30条分值较高的视频
        cacheTagToRedis(hotVideoDtoList);
    }

    @Autowired
    private VideoChannelMapper videoChannelMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 缓存30条分值较高的视频
     * @param hotVideoDtoList
     */
    private void cacheTagToRedis(List<HotVideoDto> hotVideoDtoList) {
        // 为每个频道缓存30条分值较高的视频
        List<VideoChannel> videoChannels = videoChannelMapper.selectVideoChannelList(null);
        // 检索出每个频道的视频
        for (VideoChannel videoChannel : videoChannels) {
            List<HotVideoDto> hotVideoDtos = hotVideoDtoList.stream().filter(item ->
                    item.getChannelId().equals(videoChannel.getId())
            ).collect(Collectors.toList());

            // 给视频排序, 取30条分值较高的视频存入redis key: 频道id value: 30条分值较高的视频
            sortAndCache(hotVideoDtos, "hot-" + videoChannel.getId());
        }

        // 设置推荐数据
        // 给视频排序, 取30条分值较高的视频存入redis key: 频道id value: 30条分值较高的视频
        sortAndCache(hotVideoDtoList, "hot-0");
    }

    /**
     * 排序并且缓存数据
     * @param hotVideoDtos
     * @param key
     */
    private void sortAndCache(List<HotVideoDto> hotVideoDtos, String key) {
        hotVideoDtos = hotVideoDtos.stream().sorted(
                Comparator.comparing(HotVideoDto::getScore).reversed()
        ).collect(Collectors.toList());
        if(hotVideoDtos.size() > 30){
            hotVideoDtos = hotVideoDtos.subList(0, 30);
        }
        stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(hotVideoDtos));
    }


    /**
     * 获取热视频列表
     * @param videoList
     * @return
     */
    private List<HotVideoDto> getHotVideoDtoList(List<SysVideo> videoList) {
        List<HotVideoDto> videoDtoList = new ArrayList<>();
        if(videoList!=null) {
            for (SysVideo video : videoList) {
                HotVideoDto hotVideoDto = new HotVideoDto();
                BeanUtils.copyProperties(video, hotVideoDto);
                Long score = computeArticleScore(video);
                hotVideoDto.setScore(score);
                videoDtoList.add(hotVideoDto);
            }
        }
        return videoDtoList;
    }

    /**
     * 计算视频分数
     * @param sysVideo
     * @return
     */
    public Long computeArticleScore(SysVideo sysVideo) {
        Long score = 0L;
        if(sysVideo.getLikeCount() != null){
            score += 3*sysVideo.getLikeCount();
        }
        if(sysVideo.getVideoCommentsCount() != null){
            score += 5*sysVideo.getVideoCommentsCount();
        }
        if(sysVideo.getCollectCount() != null){
            score += 8*sysVideo.getCollectCount();
        }
        if(sysVideo.getVideoWatchCount() != null){
            score += sysVideo.getVideoWatchCount();
        }
        return score;
    }

    @Override
    public void hotFresh() {
        String hotFreshJson = stringRedisTemplate.opsForValue().get("HotFresh");
        if(hotFreshJson == null){
            computeHotArticle();
            return;
        }
        LocalDateTime lastFreshTime = JSON.parseObject(hotFreshJson, LocalDateTime.class);
        LocalDateTime nowTime = LocalDateTime.now();
        Duration duration = Duration.between(lastFreshTime, nowTime);
        Long difMinutes = duration.toMinutes();
        if(difMinutes >= 1){
            computeHotArticle();
        }
    }

}
